/* Copyright (C) 2014 InfiniDB, Inc.
   Copyright (C) 2016-2021 MariaDB Corporation

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License
   as published by the Free Software Foundation; version 2 of
   the License.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
   MA 02110-1301, USA. */

/*
 * $Id: primitivemsg.h 9655 2013-06-25 23:08:13Z xlou $
 */

/** @file */

#pragma once

#include <sys/types.h>

#include "blocksize.h"
#include "calpontsystemcatalog.h"
#include "joblisttypes.h"
#include <columnwidth.h>

#include <vector>

#pragma pack(push, 1)

// from blocksize.h
const int32_t DATA_BLOCK_SIZE = BLOCK_SIZE;

const int8_t COMPARE_NIL = 0x00;  // means c = NULL predicate
const int8_t COMPARE_LT = 0x01;
const int8_t COMPARE_EQ = 0x02;
const int8_t COMPARE_LE = (COMPARE_LT | COMPARE_EQ);  // 0x03
const int8_t COMPARE_GT = 0x04;
const int8_t COMPARE_NE = (COMPARE_LT | COMPARE_GT);  // 0x05
const int8_t COMPARE_GE = (COMPARE_GT | COMPARE_EQ);  // 0x06
const int8_t COMPARE_NULLEQ = 0x07;                   // means c IS NULL(see column.cpp for details)
const int8_t COMPARE_NOT = 0x08;
const int8_t COMPARE_NLT = (COMPARE_LT | COMPARE_NOT);  // 0x09
const int8_t COMPARE_NLE = (COMPARE_LE | COMPARE_NOT);  // 0x0b
const int8_t COMPARE_NGT = (COMPARE_GT | COMPARE_NOT);  // 0x0c
const int8_t COMPARE_NGE = (COMPARE_GE | COMPARE_NOT);  // 0x0e

const int8_t COMPARE_LIKE = 0x10;
const int8_t COMPARE_NLIKE = (COMPARE_LIKE | COMPARE_NOT);  // 0x18

namespace primitives
{
using RIDType = uint16_t;
using NVALSType = uint16_t;
using utils::ConstString;

class StringComparator : public datatypes::Charset
{
 public:
  explicit StringComparator(const Charset& cs) : Charset(cs)
  {
  }
  bool op(int* error, uint8_t COP, const ConstString& str1, const ConstString& str2) const
  {
    if (COP & COMPARE_LIKE)
      return like(COP & COMPARE_NOT, str1, str2);

    if (COP == COMPARE_NULLEQ)
      return str1.isNull() ==
             str2.isNull();  // XXX: TODO: I do not know the logic here, so it is temporary solution.

    int cmp = strnncollsp(str1, str2);

    switch (COP)
    {
      case COMPARE_NIL: return false;

      case COMPARE_LT: return cmp < 0;

      case COMPARE_EQ: return cmp == 0;

      case COMPARE_LE: return cmp <= 0;

      case COMPARE_GT: return cmp > 0;

      case COMPARE_NE: return cmp != 0;

      case COMPARE_GE: return cmp >= 0;

      default: *error |= 1; return false;
    }
  }
};

}  // namespace primitives

//      BOP (Binary Operation) values
//          used to tell if the operations are all be true or
//          any to be true.

#define BOP_NONE 0
#define BOP_AND 1
#define BOP_OR 2
#define BOP_XOR 3

//		OT (Output Type) values
// 1 = RID, 2 = Token, 3 = Both

#define OT_RID 1
#define OT_TOKEN 2
#define OT_BOTH 3  // both = RID & TOKEN
#define OT_DATAVALUE 4
#define OT_INPUTARG OT_RID  // reuse OT_RID's flag in dictionary primitives.  Specifies that
// the filter argument that matched should be part of the result set.
// (only makes sense when BOP = OR).
#define OT_AGGREGATE 8  // specifies that aggregate data should be generated

//      Packet Header Types

enum PACKETTYPE
{
  NULL1 = 0,
  NULL2 = 0X0F,
  DATA = 1,
  CMD = 2,
  FLOW = 3,
  CONFIG = 9
};

enum TYPEFLOWCOMMAND
{
  ACK = 1,
  NACK = 2
};

//      Define the ISM Commands

#define PRIM_LOCALBASE 10
#define PRIM_COLBASE 50
#define PRIM_INDEXBASE 100
#define PRIM_CACHEBASE 190
#define PRIM_DICTBASE 200
#define PRIM_DELIVERBASE 250

// 8 bits only!
enum ISMPACKETCOMMAND
{
  // max of 50-10=40 commands
  LOCAL_JOIN_BY_RID = PRIM_LOCALBASE + 0,
  LOCAL_OR_BY_RID = PRIM_LOCALBASE + 1,
  ARITHMETIC_FUNCTION = PRIM_LOCALBASE + 2,
  FUNCTION_CALL = PRIM_LOCALBASE + 3,
  FUNCTION_CALL_VECTOR = PRIM_LOCALBASE + 4,
  LOCAL_COMPARE_BY_VALUE = PRIM_LOCALBASE + 5,
  LOCAL_JOIN_BY_VALUE = PRIM_LOCALBASE + 6,
  BATCH_PRIMITIVE_CREATE = PRIM_LOCALBASE + 7,
  BATCH_PRIMITIVE_RUN = PRIM_LOCALBASE + 8,
  BATCH_PRIMITIVE_DESTROY = PRIM_LOCALBASE + 9,
  BATCH_PRIMITIVE_ADD_JOINER = PRIM_LOCALBASE + 10,
  BATCH_PRIMITIVE_END_JOINER = PRIM_LOCALBASE + 11,
  BATCH_PRIMITIVE_ACK = PRIM_LOCALBASE + 12,
  BATCH_PRIMITIVE_ABORT = PRIM_LOCALBASE + 13,

  // max of 100-50=50 commands
  COL_RESULTS = PRIM_COLBASE + 0,
  COL_AGG_RESULTS = PRIM_COLBASE + 1,
  COL_BY_SCAN = PRIM_COLBASE + 2,
  COL_BY_RID = PRIM_COLBASE + 3,
  COL_AGG_BY_SCAN = PRIM_COLBASE + 4,
  COL_AGG_BY_RID = PRIM_COLBASE + 5,
  COL_JOIN_BY_SCAN = PRIM_COLBASE + 6,
  COL_FILTER_BY_TOKEN = PRIM_COLBASE + 7,
  COL_FILTER_BY_RID_VAL = PRIM_COLBASE + 8,
  COL_BY_SCAN_RANGE = PRIM_COLBASE + 9,
  COL_LOOPBACK = PRIM_COLBASE + 10,

  // max of 190-100=90 commands
  INDEX_RESULTS = PRIM_INDEXBASE + 0,                 // Obsolete ?
  INDEX_SCAN_RESULTS = PRIM_INDEXBASE + 1,            // p_IdxScan results
  INDEX_WALK_RESULTS = PRIM_INDEXBASE + 2,            // p_IdxWalk results
  INDEX_LIST_RESULTS = PRIM_INDEXBASE + 3,            // p_IdxList results
  INDEX_LIST_AGGREGATE_RESULTS = PRIM_INDEXBASE + 4,  // p_IdxListAggregate results
  INDEX_SCAN_AGGREGATE_RESULTS = PRIM_INDEXBASE + 5,  // p_IdxScanAggregate results
  INDEX_BY_SCAN = PRIM_INDEXBASE + 6,                 // p_IdxScan
  INDEX_BY_COMPARE = PRIM_INDEXBASE + 7,              // Obsolete ?
  INDEX_WALK = PRIM_INDEXBASE + 8,                    // p_IdxWalk
  INDEX_LIST = PRIM_INDEXBASE + 9,                    // p_IdxList
  INDEX_LIST_AGGREGATE = PRIM_INDEXBASE + 10,         // p_IdxListAggregate
  INDEX_SCAN_AGGREGATE = PRIM_INDEXBASE + 11,         // p_IdxScanAggregate

  // max of 200-190=10 commands
  CACHE_OP_RESULTS = PRIM_CACHEBASE + 0,       // Response msg
  CACHE_FLUSH = PRIM_CACHEBASE + 1,            // Flush the entire block cache
  CACHE_CLEAN_VSS = PRIM_CACHEBASE + 2,        // Clean out indicated VSS entries
  CACHE_DROP_FDS = PRIM_CACHEBASE + 3,         // Drop the whole file descriptor cache
  FLUSH_ALL_VERSION = PRIM_CACHEBASE + 4,      // Drop all versions of specified LBIDs
  CACHE_FLUSH_BY_OID = PRIM_CACHEBASE + 5,     // Drop all versions of all LBIDs for the given OIDs
  CACHE_FLUSH_PARTITION = PRIM_CACHEBASE + 6,  // Drop a partition
  CACHE_PURGE_FDS = PRIM_CACHEBASE + 7,        // Purge the file descriptor cache for the modified files

  // max of 250-200=50 commands
  DICT_RESULTS = PRIM_DICTBASE + 0,
  DICT_TOKEN_BY_INDEX_COMPARE = PRIM_DICTBASE + 1,
  DICT_TOKEN_BY_SCAN_COMPARE = PRIM_DICTBASE + 2,
  DICT_SIGNATURE = PRIM_DICTBASE + 3,
  DICT_AGGREGATE = PRIM_DICTBASE + 4,
  DICT_AGGREGATE_RESULTS = PRIM_DICTBASE + 5,
  DICT_SCAN_COMPARE_RESULTS = PRIM_DICTBASE + 6,
  DICT_SIGNATURE_RANGE = PRIM_DICTBASE + 7,
  DICT_CREATE_EQUALITY_FILTER = PRIM_DICTBASE + 8,
  DICT_DESTROY_EQUALITY_FILTER = PRIM_DICTBASE + 9,

  // max of 256-250=6 commands
  DELIVER_TOKEN_RESULTS = PRIM_DELIVERBASE + 0,
  DELIVER_RID_RESULTS = PRIM_DELIVERBASE + 1
};

#undef PRIM_LOCALBASE
#undef PRIM_COLBASE
#undef PRIM_INDEXBASE
#undef PRIM_DICTBASE
#undef PRIM_DELIVERBASE

/* Flags for BPP messages */
const uint16_t NEED_STR_VALUES = 0x01;        // 1;
const uint16_t GOT_ABS_RIDS = 0x02;           // 2;
const uint16_t GOT_VALUES = 0x04;             // 4;
const uint16_t LBID_TRACE = 0x08;             // 8;
const uint16_t HAS_JOINER = 0x10;             // 16;
const uint16_t SEND_RIDS_AT_DELIVERY = 0x20;  // 32;
const uint16_t HAS_ROWGROUP = 0x40;           // 64;
const uint16_t JOIN_ROWGROUP_DATA = 0x80;     // 128
const uint16_t HAS_WIDE_COLUMNS = 0x100;      // 256;

// TODO: put this in a namespace to stop global ns pollution
enum PrimFlags
{
  PF_LBID_TRACE = 0x01, /*!< Enable LBID tracing in PrimProc */
  PF_PM_PROF = 0x02,    /*!< Enable LBID tracing in PrimProc */
};

enum BPSOutputType
{
  BPS_ELEMENT_TYPE,
  STRING_ELEMENT_TYPE,
  TABLE_BAND,
  TUPLE,
  ROW_GROUP
};

//      Constant Message Header structures

//      Packet Header for VBEU & CachEU

#if 0
struct VBCPacketHeader
{
    //    unsigned char Type:4;
    //    unsigned char SubType:4;
    //    unsigned int  Size:16;
    //    unsigned int  Dest:16;
    unsigned int  Source: 16;
    unsigned char CmdAddr: 8;
};
#endif

//      Packet Header for ISM SubBlock EU

// Changing this structure one !MUST! align ColResultHeader
struct ISMPacketHeader
{
  ISMPacketHeader() : Interleave(0), Flags(0), Command(0), Size(0), Type(0), MsgCount(0), Status(0)
  {
  }
  uint32_t Interleave;
  uint16_t Flags;
  uint8_t Command;
  // !!! This attribute is used to store a sum which arg type is potentially uint64_t.
  // As of 23.02.10 uint32_t here is always enough for the purpose of this attribute though.
  uint16_t Size;
  unsigned Type : 4;
  unsigned MsgCount : 4;
  uint16_t Status;
};

//      Primitive request/response structure Header
//@Bug 2744 changed all variables to 32 bit, and took out StatementID
// Changing this structure one !MUST! align ColResultHeader
struct PrimitiveHeader
{
  uint32_t SessionID;      // Front end Session Identifier
  uint32_t TransactionID;  // Front end Transaction Identifier
  uint32_t VerID;          // DB Version ID used for this Session/Statement
  uint32_t StepID;         // Internal Primitive Sequence number
  uint32_t UniqueID;       // Unique ID for DEC and BPP
  uint32_t Priority;       // Priority level of the user
};

#if 0
struct AckNackHeader
{
    int VerID: 16;
};

struct DiskResultsHeader
{
    uint64_t    LBID;
    uint64_t    VerID;
    uint64_t    ArbIndex;
    uint64_t    ISM;
    uint64_t    Status;
    uint8_t     data[DATA_BLOCK_SIZE];
};
#endif

//      COL_LOOPBACK

struct ColLoopback
{
  PrimitiveHeader Hdr;  // 64 bit header
};

struct ColRequestHeaderDataType : public datatypes::Charset
{
  int32_t CompType;
  uint16_t DataSize;
  uint8_t DataType;  // enum ColDataType defined in calpont system catalog header file
  ColRequestHeaderDataType() : Charset(my_charset_bin), CompType(0), DataSize(0), DataType(0)
  {
  }
  explicit ColRequestHeaderDataType(const execplan::CalpontSystemCatalog::ColType& rhs)
   : Charset(rhs.charsetNumber)
   , CompType(rhs.compressionType)
   , DataSize(rhs.colWidth)
   , DataType(rhs.colDataType)
  {
  }
};

//      COL_BY_SCAN
// Tied to ColByScanRangeRequestHeader and NewColRequestHeader.  Check other headers if modifying.

struct ColByScanRequestHeader
{
  PrimitiveHeader Hdr;  // 64 bit header
  uint64_t LBID;
  ColRequestHeaderDataType colType;
  uint8_t OutputType;  // 1 = RID, 2 = Token, 3 = Both
  uint8_t BOP;         // 0 = N/A, 1 = AND, 2 = OR
  uint16_t RidFlags;   // a bitmap indicating the rid ranges in the result MSB => row 7680-8191
  uint16_t NOPS;
  uint16_t NVALS;
  uint8_t sort;
  ColByScanRequestHeader() : LBID(0), OutputType(0), BOP(0), RidFlags(0), NOPS(0), NVALS(0), sort(0)
  {
    memset(&Hdr, 0, sizeof(Hdr));
  }
};

//      COL_BY_SCAN_RANGE
// Tied to ColByScanRequestHeader and NewColRequestHeader.  Check other headers if modifying.

struct ColByScanRangeRequestHeader
{
  PrimitiveHeader Hdr;  // 64 bit header
  uint64_t LBID;        // starting LBID
  ColRequestHeaderDataType colType;
  uint8_t OutputType;  // 1 = RID, 2 = Token, 3 = Both
  uint8_t BOP;         // 0 = N/A, 1 = AND, 2 = OR
  uint16_t RidFlags;   // a bitmap indicating the rid ranges in the result MSB => row 7680-8191
  uint16_t NOPS;
  uint16_t NVALS;
  uint8_t sort;
  uint16_t Count;  // Number of LBID's
  ColByScanRangeRequestHeader()
   : LBID(0), OutputType(0), BOP(0), RidFlags(0), NOPS(0), NVALS(0), sort(0), Count(0)
  {
    memset(&Hdr, 0, sizeof(Hdr));
  }
};

//      COL_BY_RID

struct ColByRIDRequestHeader
{
  PrimitiveHeader Hdr;  // 64 bit header
  uint64_t LBID;
  ColRequestHeaderDataType colType;
  uint8_t OutputType;  // 1 = RID, 2 = Token, 3 = Both
  uint8_t BOP;         // 0 = N/A, 1 = AND, 2 = OR
  uint8_t InputFlags;  // 1 = interpret each NOP & RID as a pair
  uint16_t NOPS;
  uint16_t NVALS;
  uint8_t sort;
  ColByRIDRequestHeader();  // QQ? Not used?
};

//      COL_AGG_BY_SCAN

struct ColAggByScanRequestHeader
{
  PrimitiveHeader Hdr;  // 64 bit header
  uint64_t LBID;
  uint16_t DataSize;
  uint8_t DataType;    // enum ColDataType defined in calpont system catalog header file
  uint8_t OutputType;  // 1 = RID, 2 = Token, 3 = Both
  uint8_t BOP;         // 0 = N/A, 1 = AND, 2 = OR
  uint8_t ExtraNotUsed;
  uint16_t NOPS;
  uint16_t NVALS;
};

//      COL_AGG_BY_RID

struct ColAggByRIDRequestHeader
{
  PrimitiveHeader Hdr;  // 64 bit header
  uint64_t LBID;
  ColRequestHeaderDataType colType;
  uint8_t OutputType;  // 1 = RID, 2 = Token, 3 = Both
  uint8_t BOP;         // 0 = N/A, 1 = AND, 2 = OR
  uint8_t ExtraNotUsed;
  uint16_t NOPS;
  uint16_t NVALS;
  ColAggByRIDRequestHeader();  // Not used?
};

//      Loopback Results

struct LoopbackResultHeader
{
  PrimitiveHeader Hdr;
};

//      Column Results

//      Column Aggregate results

struct ColAggResultHeader
{
  PrimitiveHeader Hdr;
  uint64_t LBID;
  uint64_t MIN;          // Minimum value in this block (signed)
  uint64_t MAX;          // Maximum value in this block (signed)
  uint64_t SUM;          // Sum of values in this block (unsigned)
  uint32_t SUMOverflow;  // Overflow of sum (unsigned)
  uint16_t NVALS;        // Number of values in this block
  uint16_t Pad1;
};

//      INDEX_BY_SCAN

struct IndexByScanRequestHeader
{
  PrimitiveHeader Hdr;
  uint64_t LBID;
  uint32_t State;
  uint8_t Flags;
  uint8_t DataSize;
  uint8_t DataType;  // enum ColDataType defined in calpont system catalog header file
  uint8_t ExtraNotUsed;
  uint16_t NVALS;
};

//      INDEX_BY_COMPARE

struct IndexByCompareRequestHeader
{
  PrimitiveHeader Hdr;
  uint64_t LBID;
  uint32_t State;
  uint8_t Flags;
  uint8_t DataSize;
  uint8_t DataType;  // enum ColDataType defined in calpont system catalog header file
  uint8_t ExtraNotUsed;
  uint16_t NVALS;
};

struct IndexResultHeader
{
  PrimitiveHeader Hdr;
  uint64_t LBID;
  uint32_t State;
  uint16_t NVALS;
  uint16_t Pad;
};

//  p_IdxWalk

// this is used as input & output to the software p_IdxWalk processor.  Ideally
// there would only be one copy of the ISM and packet headers per returned result.

#ifdef __cplusplus
struct IndexWalkHeader
{
  ISMPacketHeader ism;
  PrimitiveHeader Hdr;
  uint64_t SearchString[2];
  const std::vector<uint64_t>* SearchStrings;  // used only if NVALS > 2
  uint8_t SSlen;                               // width of the search argument in BITS
  uint8_t Shift;                               // initialize to zero when first sending to primitive
  uint8_t BOP;
  uint8_t COP1;
  uint8_t COP2;
  uint8_t State;  // right now this is only 1 or 0, specifying entire subtrees
  uint16_t NVALS;
  uint64_t LBID : 36;
  uint8_t SubBlock : 5;
  uint8_t SBEntry : 5;
};
#endif

// p_IdxList

struct IndexListHeader
{
  ISMPacketHeader ism;
  PrimitiveHeader Hdr;
  uint64_t LBID;
  uint16_t NVALS;
  uint16_t Pad1;
  uint32_t Pad2;
  // As the input parameter, what follows is IndexListParam[NVALS]
  // As the output parameter, what follows is IndexListResult[NVALS]
};

// p_IdxList parameter
struct IndexListParam
{
  uint64_t type : 3;  // 0 - header, 4 - subblock, 5 - block
  uint64_t spare : 15;
  uint64_t fbo : 36;
  uint64_t sbid : 5;
  uint64_t entry : 5;
  // 		int64_t listValue;
};

struct IndexListEntry
{
  uint64_t type : 3;
  uint64_t spare : 5;
  uint64_t ridCt : 10;
  uint64_t value : 46;
};

struct IndexListResult
{
  IndexListEntry entry;
  int64_t listValue;
};

enum IndexListType
{
  LIST_SIZE = 0,
  EMPTY_LIST_PTR = 1,
  EMPTY_PTR = 2,
  RID = 3,
  LLP_SUBBLK = 4,
  LLP_BLK = 5,
  PARENT = 6,
  NOT_IN_USE = 7
};

//      DICT_TOKEN_BY_INDEX_COMPARE
struct DictTokenByIndexRequestHeader
{
  PrimitiveHeader Hdr;
  uint64_t LBID;
  uint16_t NVALS;
  uint16_t Pad1;
  uint32_t Pad2;
};

//      DICT_TOKEN_BY_SCAN_COMPARE

struct DataValue
{
  uint8_t isnull;
  uint16_t len;
  char data[];
};

struct NonNullDataValue
{
  uint16_t len;
  char data[];
};

struct PrimToken
{
  uint64_t LBID;
  uint16_t offset;  // measured in bytes
  uint16_t len;     // # of bytes
};

// Masks for the flags member of TokenByScanRequestHeader
#define HAS_EQ_FILTER 0x1
#define IS_SYSCAT 0x2

struct TokenByScanRequestHeader
{
  ISMPacketHeader ism;
  PrimitiveHeader Hdr;
  uint64_t LBID;
  int32_t CompType;
  uint8_t COP1;
  uint8_t COP2;
  uint8_t BOP;
  uint8_t OutputType;
  uint16_t NVALS;
  uint16_t flags;
  uint32_t Pad2;
  uint16_t Count;
  uint32_t charsetNumber;
};  // what follows is NVALS DataValues.

// compatibility with Ron's stuff.
typedef TokenByScanRequestHeader DictTokenByScanRequestHeader;

struct TokenByScanResultHeader
{
  ISMPacketHeader ism;
  PrimitiveHeader Hdr;
  uint32_t NBYTES;
  uint16_t NVALS;
  uint16_t Pad1;
  uint32_t CacheIO;     // I/O count from buffer cache
  uint32_t PhysicalIO;  // Physical I/O count from disk
};  // what follows is NVALS Tokens or DataValues.

//      DICT_SIGNATURE

struct DictSignatureRequestHeader
{
  PrimitiveHeader Hdr;
  uint64_t LBID;
  int32_t CompType;
  uint16_t NVALS;
  uint16_t Pad1;
  uint32_t Pad2;
};
// Tied to DictSignatureRequestHeader, note if modifying either.
struct DictSignatureRangeRequestHeader
{
  PrimitiveHeader Hdr;
  uint64_t LBID;
  int32_t CompType;
  uint16_t NVALS;
  uint16_t Pad1;
  uint32_t Pad2;
  uint16_t Count;
};

//      DICT_AGGREGATE

struct DictAggregateRequestHeader
{
  PrimitiveHeader Hdr;
  uint64_t LBID;
  int32_t CompType;
  uint16_t NVALS;
  uint16_t Pad1;
  uint32_t Pad2;
};

struct DictResultHeader
{
  PrimitiveHeader Hdr;
  uint64_t LBID;
  uint16_t NVALS;
  uint16_t Pad1;
  uint32_t Pad2;
};

struct AggregateSignatureRequestHeader
{
  ISMPacketHeader ism;
  PrimitiveHeader hdr;
  uint16_t NVALS;
  PrimToken tokens[];
};

struct AggregateSignatureResultHeader
{
  ISMPacketHeader ism;
  PrimitiveHeader hdr;
  uint16_t Count;
  // these implicitly follow the header
  // DataValue min;
  // DataValue max;
};

/* An array of these structures defines a filter applied by p_Col.  The length
 * of the val field should be the width of the column the filter will be applied
 * to, ex: 4 bytes long for a 32-bit column.
 */
struct ColArgs
{
  uint8_t COP;
  uint8_t rf;  // rounding flag: indicates if val is truncated or saturated
  // for further evaluation of an equal condiction
  int8_t val[];
};

// const for rf
const uint8_t ROUND_POS = 0x01;  // actual value larger/longer than the stored value
const uint8_t ROUND_NEG = 0x80;  // actual value less than the stored value

// Tied to ColByScanRequestHeader and ColByScanRangeRequestHeader.  Check other headers if modifying.
struct /*alignas(utils::MAXCOLUMNWIDTH)*/ NewColRequestHeader
{
  ISMPacketHeader ism;
  PrimitiveHeader hdr;
  uint64_t LBID;
  ColRequestHeaderDataType colType;
  uint8_t OutputType;  // OT_DATAVALUE, OT_RID, or OT_BOTH
  uint8_t BOP;
  // 	uint8_t InputFlags;		// 1 = interpret each NOP & RID as a pair (deprecated)
  uint16_t RidFlags;  // a bitmap indicating the rid ranges in the result MSB => row 7680-8191
  uint16_t NOPS;
  uint16_t NVALS;
  uint8_t sort;  // 1 to sort
  bool hasAuxCol;
  // this follows the header
  // ColArgs ArgList[NOPS] (where the val field is DataSize bytes long)
  // uint16_t Rids[NVALS]  (each rid is relative to the given block)

  // QQ: The below constructor is never used.
  // This struct is used in a cast only, in a hackish way.
  NewColRequestHeader();
  inline uint16_t* getRIDArrayPtr(const int width) const
  {
    return (NVALS > 0) ? reinterpret_cast<uint16_t*>((uint8_t*)this + sizeof(NewColRequestHeader) +
                                                     (NOPS * getFilterSize(width)))
                       : nullptr;
  }
  // WIP change to unsigned if needed
  inline int getFilterSize(const int width) const
  {
    return sizeof(uint8_t) + sizeof(uint8_t) + width;
  }
  inline uint8_t* getFilterStringPtr()
  {
    return reinterpret_cast<uint8_t*>(this) + sizeof(NewColRequestHeader);
  }
  inline void sortRIDArrayIfNeeded(const int width)
  {
    // NVALS means number of RIDs in the context of the f().
    if (NVALS > 0)
    {
      uint16_t* ridArray = getRIDArrayPtr(width);
      if (sort == 1)
        std::sort(ridArray, ridArray + NVALS);
    }
  }
};

struct NewColAggRequestHeader
{
  ISMPacketHeader ism;
  PrimitiveHeader hdr;
  uint64_t LBID;
  ColRequestHeaderDataType colType;
  uint8_t OutputType;
  uint8_t BOP;
  uint8_t ExtraNotUsed;
  uint16_t NOPS;
  uint16_t NVALS;
  // this follows the header
  // ColArgs ArgList[NOPS] (where the val field is DataSize bytes long)
  // uint16_t Rids[NVALS] (each rid is relative to the given block)
  NewColAggRequestHeader();  // QQ: not used
};

// The size of the structure !MUST! be aligned by the max(sizeof(DataType)) supported by MCS.
struct ColResultHeader
{
  PrimitiveHeader hdr;
  int128_t Min;  // Minimum value in this block for signed data types
  int128_t Max;  // Maximum value in this block for signed data types
  ISMPacketHeader ism;
  uint64_t LBID;
  uint16_t RidFlags;
  primitives::NVALSType NVALS;
  uint16_t ValidMinMax;  // 1 if Min/Max are valid, otherwise 0
  uint32_t OutputType;
  uint32_t CacheIO;     // I/O count from buffer cache
  uint32_t PhysicalIO;  // Physical I/O count from disk
  char padding[34];
  // if OutputType was OT_DATAVALUE, what follows is DataType[NVALS]
  // if OutputType was OT_RID, what follows is uint16_t Rids[NVALS]
  // if OutputType was OT_BOTH, what follows is uint16_t Rids[NVALS] DataType[NVALS]
};

namespace primitives
{
constexpr static uint32_t ColResultHeaderFirstValueOffset =
    sizeof(ColResultHeader) + sizeof(RIDType) * BLOCK_SIZE;
constexpr static uint32_t RID2FirstValueOffset = sizeof(RIDType) * BLOCK_SIZE;

template <typename T>
inline T* getValuesArrayPosition(uint8_t* out, const NVALSType offset)
{
  return reinterpret_cast<T*>(out + offset * sizeof(T));
}

inline primitives::RIDType* getRIDArrayPosition(uint8_t* out, const NVALSType offset)
{
  return getValuesArrayPosition<RIDType>(out, offset);
}

inline uint8_t* getFirstValueArrayPosition(ColResultHeader* outMsg)
{
  return reinterpret_cast<uint8_t*>(outMsg) + ColResultHeaderFirstValueOffset;
}

inline uint8_t* getFirstRIDArrayPosition(ColResultHeader* outMsg)
{
  return reinterpret_cast<uint8_t*>(&outMsg[1]);
}
}  // namespace primitives

/* additional types to support p_dictionary */
struct DictFilterElement
{
  uint8_t COP;
  uint16_t len;  // this is the length of data, not the size of the entire entry
  uint8_t data[];
};

struct DictInput
{
  ISMPacketHeader ism;
  PrimitiveHeader hdr;
  uint64_t LBID;
  uint8_t BOP;
  uint8_t InputFlags;  // 1 -> 64-bit RID, 64-bit token pairs (old p_GetSignature behavior),
  // 0-> new behavior
  uint8_t OutputType;
  uint16_t NOPS;
  uint16_t NVALS;
  PrimToken tokens[];  // NVALS of these.
                       // DictFilterElement[NOPS] filter;
};

struct DictAggregate
{
  uint16_t Count;
  // DataValue min;
  // DataValue max;
};

struct DictOutput
{
  ISMPacketHeader ism;
  PrimitiveHeader hdr;
  uint64_t LBID;
  uint16_t NVALS;
  uint16_t Pad;
  uint32_t NBYTES;
  uint32_t CacheIO;     // I/O count from buffer cache
  uint32_t PhysicalIO;  // Physical I/O count from disk
                        // What follows this header depends on OutputType.
                        // for each NVAL, what follows is ...
  //   if OutputType | OT_RID & InputFlags==1, the 64-bit RID associated with the input token
  //   if OutputType | OT_TOKEN, a PrimToken
  //   if OutputType | OT_DATAVALUE, a DataValue containing the string in the dict block
  //   if OutputType | OT_INPUT, a DataValue containing the first filter string...
  //        ... that matched (only makes sense when BOP is OR).
  // DictAggregate agg;  (if OutputType | OT_AGGREGATE)
};  // same as TokenByScanResultHeader at the moment

struct OldGetSigParams
{
  uint64_t rid;
  uint16_t offsetIndex;
};

struct LbidAtVer
{
  uint64_t LBID;
  uint32_t Ver;
};

#pragma pack(pop)
